/**
 * model.cpp is part of Gedule.
 *
 * Gedule is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Gedule is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Gedule.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "model.h"
#include "task.h"
#include "resource.h"
#include "constraints/modelconstraint.h"
#include "../utils/visitor/visitor.h"
#include <sstream>
#include <boost/foreach.hpp>

///////////////////////////////////////////////////////////////
Model::Model( const std::string & a_modelName ) :
    Visitable(),
    Printable(),
    m_tasks(),
    m_modelName( a_modelName ),
    m_constraints(),
    m_resources()
{
}

///////////////////////////////////////////////////////////////
Model::~Model()
{
    Clear();
}

///////////////////////////////////////////////////////////////
void Model::Clear()
{
    ClearTasks();
    ClearConstraints();
    ClearResources();
    m_modelName = UNNAMED;
}

///////////////////////////////////////////////////////////////
void Model::ClearTasks()
{
    BOOST_FOREACH( Task * task, m_tasks )
    {
        if( task )
            delete task;
    }

    m_tasks.clear();
}

///////////////////////////////////////////////////////////////
void Model::ClearConstraints()
{
    BOOST_FOREACH( ModelConstraint * constraint, m_constraints )
    {
        if( constraint )
            delete constraint;
    }

    m_constraints.clear();
}

///////////////////////////////////////////////////////////////
void Model::ClearResources()
{
    BOOST_FOREACH( Resource * resource, m_resources )
    {
        if( resource )
            delete resource;
    }

    m_resources.clear();
}

///////////////////////////////////////////////////////////////
void Model::Accept( Visitor * a_visitor, bool a_depthFirst )
{
    if( a_visitor )
    {
        if( !a_depthFirst )
            a_visitor->Visit( this );

        AcceptTasks( a_visitor, a_depthFirst );
        AcceptResources( a_visitor, a_depthFirst );
        AcceptConstraints( a_visitor, a_depthFirst );

        if( a_depthFirst )
            a_visitor->Visit( this );
    }
}

///////////////////////////////////////////////////////////////
void Model::AcceptTasks( Visitor * a_visitor, bool a_depthFirst )
{
    BOOST_FOREACH( Task * task, m_tasks )
    {
        if( task )
            task->Accept( a_visitor, a_depthFirst );
    }
}

///////////////////////////////////////////////////////////////
void Model::AcceptConstraints( Visitor * a_visitor, bool a_depthFirst )
{
    BOOST_FOREACH( ModelConstraint * constraint, m_constraints )
    {
        if( constraint )
            constraint->Accept( a_visitor, a_depthFirst );
    }
}

///////////////////////////////////////////////////////////////
void Model::AcceptResources( Visitor * a_visitor, bool a_depthFirst )
{
    BOOST_FOREACH( Resource * resource, m_resources )
    {
        if( resource )
            resource->Accept( a_visitor, a_depthFirst );
    }
}

///////////////////////////////////////////////////////////////
std::string Model::Print() const
{
    std::ostringstream strStream;
    strStream << "Model :" << m_modelName << std::endl;

    strStream << PrintTasks();
    strStream << PrintResources();
    strStream << PrintConstraints();

    return strStream.str();
}

///////////////////////////////////////////////////////////////
std::string Model::PrintTasks() const
{
    std::ostringstream strStream;
    strStream << "Tasks :" << std::endl;

    BOOST_FOREACH( Task * task, m_tasks )
    {
        if( task )
            strStream << task->Print() << std::endl;
    }

    return strStream.str();
}

///////////////////////////////////////////////////////////////
std::string Model::PrintConstraints() const
{
    std::ostringstream strStream;
    strStream << "Constraints :" << std::endl;

    BOOST_FOREACH( ModelConstraint * constraint, m_constraints )
    {
        if( constraint )
            strStream << constraint->Print() << std::endl;
    }

    return strStream.str();
}

///////////////////////////////////////////////////////////////
std::string Model::PrintResources() const
{
    std::ostringstream strStream;
    strStream << "Resources :" << std::endl;

    BOOST_FOREACH( Resource * resource, m_resources )
    {
        if( resource )
            strStream << resource->Print() << std::endl;
    }

    return strStream.str();
}

///////////////////////////////////////////////////////////////
void Model::Add( Task * a_task )
{
    if( a_task )
        m_tasks.insert( a_task );
}

///////////////////////////////////////////////////////////////
void Model::Add( ModelConstraint * a_constraint )
{
    if( a_constraint )
        m_constraints.insert( a_constraint );
}

///////////////////////////////////////////////////////////////
void Model::Add( Resource * a_resource )
{
    if( a_resource )
        m_resources.insert( a_resource );
}

///////////////////////////////////////////////////////////////
void Model::ModelName( const std::string & a_modelName )
{
    m_modelName = a_modelName;
}

///////////////////////////////////////////////////////////////
const std::string & Model::ModelName() const
{
    return m_modelName;
}

///////////////////////////////////////////////////////////////
std::size_t Model::NTasks() const
{
    return m_tasks.size();
}

///////////////////////////////////////////////////////////////
std::size_t Model::NResources() const
{
    return m_resources.size();
}

///////////////////////////////////////////////////////////////
std::size_t Model::NConstraints() const
{
    return m_constraints.size();
}
